#ifndef COROUTINE_SINGLE_THREAD_SCHEDULER_H
#define COROUTINE_SINGLE_THREAD_SCHEDULER_H

#include "task.h"
#include <thread>
#include <vector>
#include <algorithm>
#include <cstring>

class SingleThreadScheduler {
public:
    explicit SingleThreadScheduler(const std::string& name) : thread_name(name) {};
    SingleThreadScheduler(int32_t priority, const std::string& name) :
        thread_name(name),
        thread_priority(priority),
        is_set_priority(true) {};

    ~SingleThreadScheduler() {
        fiber_deinit();
    }

    void init() {
        scheduler_handler = std::make_unique<std::thread>([this]{scheduler();});
        pthread_setname_np(scheduler_handler->native_handle(), thread_name.c_str());
        if (is_set_priority) {
            pthread_setschedprio(scheduler_handler->native_handle(), thread_priority);
        }
    }

    void scheduler() {
        //对所有Task进行初始化（申请栈，makecontext,保存调度器的context的指针）
        for (auto& task : tasks) {
            task->task_init(&context);
        }

        while (true) {
            if (!running) {
                //收到退出信号后，等待所有task执行结束
                bool all_task_finished = true;
                for (auto& task : tasks) {
                    all_task_finished &= task->get_finished();
                }
                if (all_task_finished) {
                    break;
                }
            }

            if (tasks.empty()) {
                std::this_thread::sleep_for(std::chrono::milliseconds(free_sleep_time));
                continue;
            }

            //找出最小过期时间任务的索引
            std::size_t index{0};
            int64_t min_next_run_time = INT64_MAX;
            for (std::size_t i=0; i<tasks.size(); ++i) {
                if (tasks[i]->get_next_run_time() < min_next_run_time) {
                    min_next_run_time = tasks[i]->get_next_run_time();
                    index = i;
                }
            }

            //计算next_run_time最小的任务(tasks[index])的过期时间（sleep_time）
            int64_t sleep_time = tasks[index]->get_next_run_time() - Task::get_timestamp_ms();
            //如果过期时间<=1ms并且该任务是周期任务，切换到task并运行，task应在适当的时候主动执行task_yield放弃cpu返回当前断点
            if ((sleep_time <= 1) && (!tasks[index]->get_finished())) {
                libucontext_swapcontext(&context, tasks[index]->get_entry_context());
                continue;
            }
            //如果过期时间比较长，则重置过期时间，防止错过退出信号
            if (sleep_time > free_sleep_time) {
                sleep_time = free_sleep_time;
            }

            std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
        }
    }

    void add_task(std::unique_ptr<Task>&& task) {
        tasks.emplace_back(std::move(task));
    }

    void fiber_deinit() {
        running = false;
        for (auto task = tasks.rbegin(); task != tasks.rend(); ++task) {
            (*task)->set_exit();
        }
        if (scheduler_handler != nullptr) {
            scheduler_handler->join();
            scheduler_handler = nullptr;
        }
        for (auto& task : tasks) {
            if (task != nullptr) {
                task = nullptr;
            }
        }
    }

protected:
    std::vector<std::unique_ptr<Task>> tasks{};
    std::unique_ptr<std::thread> scheduler_handler{nullptr};
    std::string thread_name{};
    int32_t thread_priority{};
    bool is_set_priority{false};
    bool running{true};
    libucontext_ucontext_t context{};
    const uint32_t free_sleep_time{100U};
};


#endif //COROUTINE_SINGLE_THREAD_SCHEDULER_H
